﻿using System.Collections.Generic;
using NUnit.Framework;
using System.IO;
using Ninject;

using System.Net.DnsToolkit.Configuration;
using System.Net.DnsToolkit.Packet;
using System.Net.DnsToolkit.Packet.Records;
using System.Net.DnsToolkit.Util;
using System.Net.DnsToolkit.Serializer;
using System.Net.DnsToolkit.Packet.Busy;
using System.Net.DnsToolkit.Packet.Busy.Records;

namespace System.Net.DnsToolkit.TestUnit.Util {
    
    [TestFixture]
    public class JsonMessageWriterTest {

        private IKernel _kernel;
        [SetUp]
        public void SetUp() {
            _kernel = new StandardKernel(new DnsWriterJsonModule());
        }

        [Test]
        public void TestQuestion1() {


            var message = new Message {
                Header = new Header {
                    Id = 1,
                    // flags
                    QueryType = QREnum.QUERY,
                    OpCode = OpCodeEnum.StandardQuery,
                    AuthoritativeAnswer = false,
                    Truncation = false,
                    RecursionDesired = true,
                    RecursionAvailable = false,
                    Reserved = false,
                    AnswerAuthenticated = false,
                    NotAuthenticatedAcceptable = false,
                    ResponseCode = RCodeEnum.NoError,
                    // counts
                    QuestionCount = 1,
                    ResourceCount = 0,
                    AnswerCount = 0,
                    AuthorityCount = 0,
                },
                Questions = new List<IQuestion> {
                    new Question {
                        QName = new DomainName { Name = "www.domn.tl." },
                        QType = QTypeEnum.A,
                        QClass = QClassEnum.IN
                    }
                }
            };

            var sw = new StringWriter();
            var writer = _kernel.Get<IMessageWriter<TextWriter>>();
            writer.Write(sw, message, false);

            var actual = sw.ToString();
            const string expected = @"{
  ""Header"": {
    ""Id"": 1,
    ""QueryType"": ""QUERY""/* 0 */,
    ""OpCode"": ""StandardQuery""/* 0 */,
    ""AuthoritativeAnswer"": false,
    ""Truncation"": false,
    ""RecursionDesired"": true,
    ""RecursionAvailable"": false,
    ""Reserved"": false,
    ""AnswerAuthenticated"": false,
    ""NotAuthenticatedAcceptable"": false,
    ""ResponseCode"": ""NoError""/* 0 */,
    ""QuestionCount"": 1,
    ""AnswerCount"": 0,
    ""AuthorityCount"": 0,
    ""ResourceCount"": 0
  },
  ""Questions"": [
    {
      ""QName"": {
        ""Name"": ""www.domn.tl.""
      },
      ""QType"": ""A""/* 1 */,
      ""QClass"": ""IN""/* 1 */
    }
  ],
  ""Answers"": [],
  ""Authorities"": [],
  ""Additionals"": []
}
";
            
            Assert.AreEqual(expected, actual, "TestQuestion1");
        }


        [Test]
        public void TestQuestion2() {


            var message = new Message {
                Header = new Header {
                    Id = 2,
                    // flags
                    QueryType = QREnum.RESPONSE,
                    OpCode = OpCodeEnum.StandardQuery,
                    AuthoritativeAnswer = false,
                    Truncation = false,
                    RecursionDesired = true,
                    RecursionAvailable = false,
                    Reserved = false,
                    AnswerAuthenticated = false,
                    NotAuthenticatedAcceptable = false,
                    ResponseCode = RCodeEnum.NoError,
                    // counts
                    QuestionCount = 1,
                    ResourceCount = 0,
                    AnswerCount = 1,
                    AuthorityCount = 0,
                },
                Questions = new List<IQuestion> {
                    new Question {
                        QName = new DomainName { Name = "www.domn.tl." },
                        QType = QTypeEnum.A,
                        QClass = QClassEnum.IN
                    }
                },
                Answers = new List<IRR> {
                    new RR {
                        Name = new DomainName { Name = "www.domn.tl." },
                        RRType = QTypeEnum.A,
                        RRClass = QClassEnum.IN,
                        Ttl = 10,
                        RDLength = 18,
                        RData = new RecordA {
                            Address = IPAddress.Parse("1.2.3.4")
                        }
                    }
                }
            };

            var sw = new StringWriter();
            var writer = _kernel.Get<IMessageWriter<TextWriter>>();
            writer.Write(sw, message, false);
            string actual = sw.ToString();

            const string expected = @"{
  ""Header"": {
    ""Id"": 2,
    ""QueryType"": ""RESPONSE""/* 1 */,
    ""OpCode"": ""StandardQuery""/* 0 */,
    ""AuthoritativeAnswer"": false,
    ""Truncation"": false,
    ""RecursionDesired"": true,
    ""RecursionAvailable"": false,
    ""Reserved"": false,
    ""AnswerAuthenticated"": false,
    ""NotAuthenticatedAcceptable"": false,
    ""ResponseCode"": ""NoError""/* 0 */,
    ""QuestionCount"": 1,
    ""AnswerCount"": 1,
    ""AuthorityCount"": 0,
    ""ResourceCount"": 0
  },
  ""Questions"": [
    {
      ""QName"": {
        ""Name"": ""www.domn.tl.""
      },
      ""QType"": ""A""/* 1 */,
      ""QClass"": ""IN""/* 1 */
    }
  ],
  ""Answers"": [
    {
      ""Name"": {
        ""Name"": ""www.domn.tl.""
      },
      ""RRType"": ""A""/* 1 */,
      ""RRClass"": ""IN""/* 1 */,
      ""Ttl"": 10,
      ""RDLength"": 18,
      ""RData"": {
        ""Address"": ""1.2.3.4"",
        ""QType"": ""A""/* 1 */
      }
    }
  ],
  ""Authorities"": [],
  ""Additionals"": []
}
";
            Assert.AreEqual(expected, actual, "TestQuestion1");
        }
    }
}
